package br.uniceub.fsw.agenda.model.dao;

import br.uniceub.fsw.agenda.exception.BusinessException;
import br.uniceub.fsw.agenda.exception.DatabaseException;
import br.uniceub.fsw.agenda.exception.UniqueConstraintException;
import br.uniceub.fsw.agenda.model.vo.BairroVO;
import br.uniceub.fsw.agenda.model.vo.CidadeVO;
import br.uniceub.fsw.agenda.util.NumberUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * 05/04/2008
 * @author Rodrigo Uchôa - rodrigo.uchoa@yahoo.com
 *
 */
public class BairroDAO extends GenericDAO {
    
    public BairroDAO(Connection con) {
        super(con);
    }
    
    /**
     * Retorna lista com todos os bairros ordenados por ordem alfabetica
     * @return List com objetos Bairro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<BairroVO> findAll() throws DatabaseException {
        //string de consulta
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_BAIRRO ORDER BY NO_BAIRRO");
        
        //lista pra armazenar o resultado
        List<BairroVO> listaRegistros = new ArrayList<BairroVO>();
        
        try {
            Statement st = con.createStatement();
            ResultSet rs = st.executeQuery(query.toString());
            while (rs.next()) {
                BairroVO bairro = new BairroVO();
                bairro.setIdBairro(rs.getInt("ID_BAIRRO"));

                CidadeVO cidade = new CidadeVO();
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                cidade = cidadeDAO.findById(NumberUtils.toInteger(rs.getString("ID_CIDADE")));
                
                bairro.setCidade(cidade);
                
                bairro.setNoBairro(rs.getString("NO_BAIRRO"));
                
                listaRegistros.add(bairro);
            }
            st.close();
            rs.close();
            return listaRegistros;            
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.findAll()", ex);
        }
    }
    
    /**
     * Retorna uma lista de bairros de uma cidade especifica, ordenados
     * por ordem alfabetica
     * @param idCidade código da cidade
     * @return List com objetos Bairro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<BairroVO> findBairrosByCidade(Integer idCidade) throws DatabaseException {
        //montar consulta
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_BAIRRO");
        query.append(" WHERE ID_CIDADE = ?");
        query.append(" ORDER BY NO_BAIRRO");
        
        List<BairroVO> listaRegistros = new ArrayList<BairroVO>();
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setInt(1, idCidade);
            
            ResultSet rs = st.executeQuery();
            while (rs.next()) {
                BairroVO bairro = new BairroVO();
                bairro.setIdBairro(rs.getInt("ID_BAIRRO"));
                bairro.setNoBairro(rs.getString("NO_BAIRRO"));

                CidadeVO cidade = new CidadeVO();
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                cidade = cidadeDAO.findById(NumberUtils.toInteger(rs.getString("ID_CIDADE")));
                
                bairro.setCidade(cidade);
                
                listaRegistros.add(bairro);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.findBairrosByCidade()", ex);
        }        
    }
    
    /**
     * Busca bairro pelo seu ID (primary key)
     * @param idBairro código do bairro
     * @return objeto Bairro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public BairroVO findById(Integer idBairro) throws DatabaseException {
        String query = "SELECT * FROM TB_BAIRRO WHERE ID_BAIRRO = ?";
        
        try {
            PreparedStatement st = con.prepareStatement(query);
            st.setInt(1, idBairro);
            
            ResultSet rs = st.executeQuery();
            BairroVO bairro = null;
            while (rs.next()) {
                bairro = new BairroVO();
                bairro.setIdBairro(rs.getInt("ID_BAIRRO"));

                CidadeVO cidade = new CidadeVO();
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                cidade = cidadeDAO.findById(NumberUtils.toInteger(rs.getString("ID_CIDADE")));
                
                bairro.setCidade(cidade);

                bairro.setNoBairro(rs.getString("NO_BAIRRO"));                
            }
            rs.close();
            st.close();
            return bairro;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.findById()", ex);
        }
    }


    /**
     * Buscar lista de bairros por parte de seu nome
     * @param noBairro parte do nome dos bairros que se deseja buscar
     * @return List de objetos Bairro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<BairroVO> findAllByNome(String noBairro) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_BAIRRO WHERE NO_BAIRRO LIKE ? ORDER BY NO_BAIRRO");
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            String filtro = "%" + noBairro + "%";
            st.setString(1, filtro);
            
            List<BairroVO> listaRegistros = new ArrayList<BairroVO>();
            
            ResultSet rs = st.executeQuery();

            while (rs.next()) {
                BairroVO bairro = new BairroVO();
                bairro.setIdBairro(rs.getInt("ID_BAIRRO"));
                bairro.setNoBairro(rs.getString("NO_BAIRRO"));

                CidadeVO cidade = new CidadeVO();
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                cidade = cidadeDAO.findById(NumberUtils.toInteger(rs.getString("ID_CIDADE")));
                
                bairro.setCidade(cidade);
                
                listaRegistros.add(bairro);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.findAllByNome()", ex);
        }
    }

    /**
     * Buscar lista de bairros por Cidade
     * @param idCidade sigla da Cidade das bairros que se deseja buscar
     * @return List de objetos Bairro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<BairroVO> findAllByCidade(Integer idCidade) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_BAIRRO WHERE ID_CIDADE = ? ORDER BY NO_BAIRRO");
        
        try {
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, idCidade.toString());
            
            List<BairroVO> listaRegistros = new ArrayList<BairroVO>();
            
            ResultSet rs = st.executeQuery();

            while (rs.next()) {
                BairroVO bairro = new BairroVO();
                bairro.setIdBairro(rs.getInt("ID_BAIRRO"));
                bairro.setNoBairro(rs.getString("NO_BAIRRO"));

                CidadeVO cidade = new CidadeVO();
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                cidade = cidadeDAO.findById(NumberUtils.toInteger(rs.getString("ID_CIDADE")));
                
                bairro.setCidade(cidade);
                
                listaRegistros.add(bairro);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.findAllByCidade()", ex);
        }
    }

    /**
     * Buscar lista de bairros pelo nome e por Cidade
     * @param noBairro nome da Bairro das bairros que se deseja buscar
     * @param idCidade sigla da Cidade das bairros que se deseja buscar
     * @return List de objetos Bairro
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public List<BairroVO> findAllByNomeAndCidade(String noBairro, Integer idCidade) throws DatabaseException {
        StringBuilder query = new StringBuilder();
        query.append("SELECT * FROM TB_BAIRRO WHERE ID_CIDADE = ? AND NO_BAIRRO LIKE ? ORDER BY NO_BAIRRO");
        
        try {
            String filtro = "%" + noBairro + "%";
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, idCidade.toString());
            st.setString(2, filtro);
            
            List<BairroVO> listaRegistros = new ArrayList<BairroVO>();
            
            ResultSet rs = st.executeQuery();

            while (rs.next()) {
                BairroVO bairro = new BairroVO();
                bairro.setIdBairro(rs.getInt("ID_BAIRRO"));
                bairro.setNoBairro(rs.getString("NO_BAIRRO"));

                CidadeVO cidade = new CidadeVO();
                CidadeDAO cidadeDAO = new CidadeDAO(this.con);
                
                cidade = cidadeDAO.findById(NumberUtils.toInteger(rs.getString("ID_CIDADE")));
                
                bairro.setCidade(cidade);
                
                listaRegistros.add(bairro);
            }
            st.close();
            rs.close();
            return listaRegistros;
        } catch (SQLException ex) {
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.findAllByCidade()", ex);
        }
    }

    /**
     * Faz o insert de um novo bairro e devolve a o id recem gerado
     * @param Bairro bairro que se deseja inserir
     * @return ID auto-increment gerado para esse registro
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public Integer insert(BairroVO bairro) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("INSERT INTO TB_BAIRRO(NO_BAIRRO, ID_CIDADE) ");
        query.append("VALUES (?,?)");
        
        //retornar id gerado
        Integer generatedId = null;
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, bairro.getNoBairro());
            st.setString(2, bairro.getCidade().getIdCidade().toString());
            
            st.executeUpdate();
            
            //pegar id gerado
            ResultSet rs = st.getGeneratedKeys();
            while (rs.next()) {
                generatedId = new Integer(rs.getString(1));                
            }                    
            
            return generatedId;            
        } catch (SQLException ex) {            
            ex.printStackTrace();
            if (ex.getErrorCode() == 1062) {
                throw new UniqueConstraintException(ex.getMessage(), ex);                
            }
            throw new DatabaseException("Erro no DAOBairro.insert()", ex);            
        }      
    }
    
    /**
     * Faz o update de uma bairro
     * @param Bairro bairro que se deseja alterar
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public void update(BairroVO bairro) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("UPDATE TB_BAIRRO SET NO_BAIRRO = ?, ID_CIDADE = ? ");
        query.append("WHERE ID_BAIRRO = ?");
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, bairro.getNoBairro());
            st.setString(2, bairro.getCidade().getIdCidade().toString());
            st.setString(3, bairro.getIdBairro().toString());
            
            st.executeUpdate();
        } catch (SQLException ex) {            
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.update()", ex);
        }      
    }
    
    /**
     * Faz o delete de um bairro
     * @param Bairro bairro que se deseja excluir
     * @throws br.uniceub.fsw.agenda.exception.BusinessException
     * @throws br.uniceub.fsw.agenda.exception.DatabaseException
     */
    public void delete(BairroVO bairro) throws BusinessException, DatabaseException {        
        StringBuilder query = new StringBuilder();
        query.append("DELETE FROM TB_BAIRRO ");
        query.append("WHERE ID_BAIRRO = ?");
        
        try {           
            PreparedStatement st = con.prepareStatement(query.toString());
            st.setString(1, bairro.getIdBairro().toString());
            
            st.executeUpdate();
        } catch (SQLException ex) {            
            ex.printStackTrace();
            throw new DatabaseException("Erro no DAOBairro.delete()", ex);            
        }      
    }

}
